package pp.aibek.bellek;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import pp.aibek.uygulama.Dosya;

public class BellekYonetici {
	private static final int BELLEK_BOYUTU = 100;

	private int bosAlan = BELLEK_BOYUTU; // Bos bellek alanini gosterir
	private int isaretci = 0;
	private List<Dosya> tablo = new ArrayList<Dosya>();
	private SekizliBolme[] bellek = new SekizliBolme[BELLEK_BOYUTU];

	public int getBosAlanBuyuklugu() {
		return bosAlan;
	}

	// Dosya bellekte varsa getirir
	public Dosya bellektenDosyaGetir(Dosya dosya) {
		if (tablo.contains(dosya)) {
			return tablo.get(tablo.indexOf(dosya));
		}
		return null;
	}

	// Bellege dosya yerlestirir
	public void bellegeDosyaYerlestir(Dosya dosya) {
		if (bosAlan >= dosya.getBoyutu()) {
			yerlestir(dosya);
		} else {
			yerAc(dosya.getBoyutu());
			yerlestir(dosya);
		}
	}

	private void yerlestir(Dosya dosya) {
		dosya.setBaslangicAdres(isaretci);
		dosya.setYuklendigiZaman(Calendar.getInstance().getTime());
		tablo.add(dosya);

		int bas = 0;
		int son = 8;
		while (bas < dosya.getDeger().length()) {
			if (son > dosya.getDeger().length()) {
				son = dosya.getDeger().length();
			}
			bellek[isaretci++] = new SekizliBolme(dosya.getDeger().substring(
					bas, son));
			bas = son;
			son += 8;
		}
	}

	private void yerAc(Integer gerekliYer) {
		List<Dosya> boyutaGoreSiraliTablo = new ArrayList<Dosya>(tablo.size());
		Collections.copy(boyutaGoreSiraliTablo, tablo);
		Collections.sort(boyutaGoreSiraliTablo, new BoyutaGore());

		boolean tekDosyaSilmekYeterli = false;
		for (Dosya dosya : boyutaGoreSiraliTablo) {
			if (bosAlan + dosya.getBoyutu() >= gerekliYer) {
				dosyaSil(dosya);
				tekDosyaSilmekYeterli = true;
				break;
			}
		}

		if (tekDosyaSilmekYeterli) {
			return;
		} else {
			Collections.reverse(boyutaGoreSiraliTablo);
			List<Dosya> silinecekDosyalar = new ArrayList<Dosya>();
			int bosaltilanAlan = bosAlan;
			for (Dosya silinecek : boyutaGoreSiraliTablo) {
				bosaltilanAlan += silinecek.getBoyutu();
				silinecekDosyalar.add(silinecek);
				if (bosaltilanAlan >= gerekliYer) {
					break;
				}
			}
			for (Dosya silinecek : silinecekDosyalar) {
				dosyaSil(silinecek);
			}
		}
	}

	private void dosyaSil(Dosya silinecek) {
		tablo.remove(silinecek);
		isaretci -= silinecek.getBoyutu();
		for (Dosya dosya : tablo) {
			if (dosya.getBaslangicAdres() > silinecek.getBaslangicAdres()) {
				dosyaYeriniOtele(dosya, silinecek.getBoyutu());
			}
		}
	}

	private void dosyaYeriniOtele(Dosya dosya, Integer otelenecekYer) {
		for (int i = dosya.getBaslangicAdres(); i < dosya.getBaslangicAdres()
				+ dosya.getBoyutu(); i++) {
			bellek[i - otelenecekYer] = bellek[i];
		}
	}

	private class BoyutaGore implements Comparator<Dosya> {
		@Override
		public int compare(Dosya o1, Dosya o2) {
			return o1.getBoyutu().compareTo(o2.getBoyutu());
		}
	}
}
